/**    
 * 文件名：BillCancelService.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年8月17日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.billcancel.service;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.logic.common.security.SecurityUtils;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.ProduceType;
import com.logic.landseaserver.common.enums.BillStatusEnum;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.BillResultCode;
import com.logic.landseaserver.common.util.Arith;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.common.util.LandSeaUtil;
import com.logic.landseaserver.domain.BalanceSheetRecord;
import com.logic.landseaserver.domain.Bill;
import com.logic.landseaserver.domain.BillDetail;
import com.logic.landseaserver.domain.Contract;
import com.logic.landseaserver.domain.Expenses;
import com.logic.landseaserver.domain.MonthlyBill;
import com.logic.landseaserver.domain.RealBill;
import com.logic.landseaserver.domain.Room;
import com.logic.landseaserver.models.billcancel.BillTypeChecker;
import com.logic.landseaserver.models.billcancel.bean.MeterReadCancelReq;
import com.logic.landseaserver.models.billcancel.bean.MeterReadResp;
import com.logic.landseaserver.models.billcancel.bean.MonthlyBillInsertBalanceSheet;
import com.logic.landseaserver.models.billcancel.bean.NoneMeterReadCancelReq;
import com.logic.landseaserver.models.billcancel.bean.ReadBillCancelReq;
import com.logic.landseaserver.models.billcancel.bean.RealBillInsertBalanceSheet;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.persistence.read.BalanceSheetRecordReadMapper;
import com.logic.landseaserver.persistence.read.BillDetailReadMapper;
import com.logic.landseaserver.persistence.read.BillReadMapper;
import com.logic.landseaserver.persistence.read.CheckFeeListReadMapper;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.persistence.read.ExpensesReadMapper;
import com.logic.landseaserver.persistence.read.MonthlyBillReadMapper;
import com.logic.landseaserver.persistence.read.RealBillReadMapper;
import com.logic.landseaserver.persistence.read.RoomReadMapper;
import com.logic.landseaserver.persistence.write.BalanceSheetRecordWriteMapper;
import com.logic.landseaserver.persistence.write.BillDetailWriteMapper;
import com.logic.landseaserver.persistence.write.BillWriteMapper;
import com.logic.landseaserver.persistence.write.ExpensesWriteMapper;
import com.logic.landseaserver.persistence.write.MonthlyBillWriteMapper;
import com.logic.landseaserver.persistence.write.RealBillWriteMapper;
import com.logic.landseaserver.ws.dto.RealBillDTO;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：BillCancelService</br>
 * 类描述：账单勾销</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年8月17日 下午10:25:56</br>
 * 
 * @version 1.0
 *
 */
@Service
public class BillCancelService
{
	private static final Logger LOGGER = LoggerFactory.getLogger(BillCancelService.class);

	@Autowired
	private RealBillReadMapper realBillReadMapper;

	@Autowired
	private RealBillWriteMapper realBillWriteMapper;

	@Autowired
	private BalanceSheetRecordWriteMapper balanceSheetWriteMapper;

	@Autowired
	private BalanceSheetRecordReadMapper balanceSheetRecordReadMapper;

	@Autowired
	private ContractReadMapper contractReadMapper;

	@Autowired
	private BillReadMapper billReadMapper;

	@Autowired
	private BillDetailReadMapper billDetailReadMapper;

	@Autowired
	private BillDetailWriteMapper billDetailWriteMapper;

	@Autowired
	private MonthlyBillWriteMapper monthlyBillWriteMapper;

	@Autowired
	private BillWriteMapper billWriteMapper;

	@Autowired
	private MonthlyBillReadMapper monthlyBillReadMapper;

	@Autowired
	private ExpensesReadMapper expensesReadMapper;

	@Autowired
	private ExpensesWriteMapper expensesWriteMapper;

	@Autowired
	private RoomReadMapper roomReadMapper;

	@Autowired
	private BillIndependentService billIndependentService;

	@Autowired
	private CheckFeeListReadMapper checkFeeListReadMapper;

	/**
	 * 
	 * [简要描述]：实时账单勾销</br>
	 * [详细描述]：需要事务</br>
	 * [作者]：Aaron(2017-08-24)</br>
	 *
	 * @param readBillCancelReq
	 * @throws LandseaException
	 *
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
	public Integer readBillCancel(ReadBillCancelReq readBillCancelReq)
			throws LandseaException
	{
		try
		{
			// 校验账单是否满足勾销
			Integer billId = readBillCancelReq.getBillId();

			// 实时账单
			RealBillDTO realBill = realBillReadMapper.selectDTOByPrimaryKey(billId);

			if (null == realBill)
			{
				// 账单不存在
				LOGGER.error("readBillCancel|账单勾销|实时账单不存在.BillId=" + billId);
				throw LandseaException.createException(BillResultCode.E00450001);
			}

			// 已支付的账单无法勾销
			if (BillStatusEnum.BIST2.getCode() == realBill.getStatus())
			{
				LOGGER.error("readBillCancel|账单勾销|账单已支付无法勾销.BillId=" + billId);
				throw LandseaException.createException(BillResultCode.E00450002);
			}

			// 判断勾销金额
			Double cancelMoney = readBillCancelReq.getCancelMoney();
			// 要转换成0.00
			cancelMoney = LandSeaUtil.get2Double(cancelMoney);

			//将独立账单的上一笔钱修改成购销状态，此时实时账单的编号是唯一的根据billNo修改状态
			//            BalanceSheetRecord editProduceType = new BalanceSheetRecord();
			//            editProduceType.setBillNo(realBill.getBillNo());
			//            editProduceType.setBillId(billId);
			//            editProduceType.setBillType(LandeaConstants.BillType.REALTIME_BILL);
			//            editProduceType.setProduceType(ProduceType.CANCEL);
			//            editProduceType.setLastModifiedBy(SecurityUtils.getCurrentLogin().getUserId());
			//            editProduceType.setLastModifiedDtm(new Date());
			//            balanceSheetWriteMapper.updateByBillNo(editProduceType);
			//修改produceType
			realUpdateProduceType(billId);

			// 勾销金额为0
			if (0.00d == cancelMoney.doubleValue())
			{
				// 删除实时账单
				realBillWriteMapper.deleteByPrimaryKey(realBill);

				// 新增负数原始金额记录到应收实收汇总表
				RealBillInsertBalanceSheet realBillCancleDTO = new RealBillInsertBalanceSheet();
				realBillCancleDTO.setRealBill(realBill);
				realBillCancleDTO.setProduceType(ProduceType.CANCEL);
				realBillCancleDTO.setAmountReceived(-realBill.getBillPrice());
				realBillCancleDTO.setReceivableMoney(-realBill.getBillPrice());
				realBillCancleDTO.setBillStatus(BillStatusEnum.BIST2.getCode());
				realBillCancleDTO.setMark(readBillCancelReq.getMark());
				Date payTime = new Date();
				realBillCancleDTO.setPayTime(payTime);
				insertBalanceSheet(realBillCancleDTO);
				//修改produceType
				realUpdateProduceType(billId);
				// 平账操作
				billIndependentService.realUpdateBalanceSheet(billId, payTime);


				return realBill.getContractId(); 
			}
			// 修改实时账单表金额为勾销金额
			RealBill updateRealBill = new RealBill();
			updateRealBill.setId(realBill.getId());
			updateRealBill.setBillPrice(cancelMoney);
			updateRealBill.setComment(readBillCancelReq.getMark());
			realBillWriteMapper.updateByPrimaryKeySelective(updateRealBill);

			// 新增负数原始金额记录到应收实收汇总表
			RealBillInsertBalanceSheet realBillCancleDTO = new RealBillInsertBalanceSheet();
			realBillCancleDTO.setRealBill(realBill);
			realBillCancleDTO.setProduceType(ProduceType.CANCEL);
			realBillCancleDTO.setAmountReceived(0.00);
			realBillCancleDTO.setReceivableMoney(-realBill.getBillPrice());
			realBillCancleDTO.setBillStatus(BillStatusEnum.BIST3.getCode());
			realBillCancleDTO.setMark(readBillCancelReq.getMark());
			insertBalanceSheet(realBillCancleDTO);

			// 新增勾销金额记录到应收实收汇总表
			realBillCancleDTO.setReceivableMoney(cancelMoney);
			realBillCancleDTO.setProduceType(ProduceType.PAY);
			insertBalanceSheet(realBillCancleDTO);

			return realBill.getContractId();
		}
		catch (LandseaException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			LOGGER.error("readBillCancel|实时账单勾销|勾销发生错误.BillId=" + readBillCancelReq.getBillId(), e);
			throw LandseaException.createException(BillResultCode.E00450008);
		}
	}

	public void realUpdateProduceType(Integer billId)
			throws LandseaException
	{
		RealBill bill = realBillReadMapper.selectByPrimaryKey(billId);

		Map<String, Object> editRecord = new HashMap<String, Object>();
		editRecord.put("billId", billId);
		editRecord.put("billType", LandeaConstants.BillType.REALTIME_BILL);
		editRecord.put("billMonth", bill.getBillMonth());
		editRecord.put("expenditureCode", bill.getExpenseType());
		List<BalanceSheetRecord> balanceSheetRecords = balanceSheetRecordReadMapper.selectEditRecord(editRecord);

		if (null == balanceSheetRecords)
		{
			return;
		}

		for (BalanceSheetRecord balanceSheetRecord : balanceSheetRecords)
		{
			balanceSheetRecord.setProduceType(ProduceType.CANCEL);
			balanceSheetRecord.setLastModifiedBy(SecurityUtils.getCurrentLogin().getUserId());
			balanceSheetRecord.setLastModifiedDtm(new Date());
			balanceSheetWriteMapper.updateByPrimaryKeySelective(balanceSheetRecord);
		}
	}

	/**
	 * 
	 * [简要描述]：新增金额记录到应收实收汇总表</br>
	 * [详细描述]：</br>
	 * [作者]：Aaron(2017-08-28)</br>
	 *
	 */
	private void insertBalanceSheet(RealBillInsertBalanceSheet insertObject)
	{
		BalanceSheetRecord balanceSheetRecordInsert = new BalanceSheetRecord();
		RealBillDTO realBill = insertObject.getRealBill();
		// 存入bill_id
		balanceSheetRecordInsert.setBillId(realBill.getId());
		// 已收金额
		Double amountReceived = LandSeaUtil.get2Double(insertObject.getAmountReceived());
		balanceSheetRecordInsert.setAmountReceived(amountReceived);
		// 应收金额
		Double receivableMoney = LandSeaUtil.get2Double(insertObject.getReceivableMoney());
		balanceSheetRecordInsert.setReceivableMoney(receivableMoney);
		balanceSheetRecordInsert.setBillMonth(realBill.getBillMonth());
		balanceSheetRecordInsert.setBillNo(realBill.getBillNo());

		// 账单的类型
		balanceSheetRecordInsert.setBillType(LandeaConstants.BillType.REALTIME_BILL);

		// 独立账单表中状态直接是支付成功
		balanceSheetRecordInsert.setBillStatus(insertObject.getBillStatus());

		Contract contract = contractReadMapper.selectByPrimaryKey(realBill.getContractId());
		if (null != contract)
		{
			balanceSheetRecordInsert.setContractNo(contract.getContractNo());
			balanceSheetRecordInsert.setContractId(contract.getId());
		}
		else
		{
			LOGGER.error("readBillCancel|账单勾销|合同不存在.ContractId=" + realBill.getContractId());
		}

		balanceSheetRecordInsert.setCreateTime(realBill.getCreatedDtm());
		balanceSheetRecordInsert.setEndTime(null);
		balanceSheetRecordInsert.setStartTime(realBill.getCreatedDtm());

		balanceSheetRecordInsert.setExpenditure(realBill.getExpenseTypeDesc());
		balanceSheetRecordInsert.setExpenditureCode(realBill.getExpenseType());
		balanceSheetRecordInsert.setRoomId(contract.getRoomId());
		Room room = roomReadMapper.selectByPrimaryKey(contract.getRoomId());
		balanceSheetRecordInsert.setHouseNum(room.getHouseNum());
		// 支付时间判断
		if (null != insertObject.getPayTime())
		{
			balanceSheetRecordInsert.setPayTime(insertObject.getPayTime());
		}

		// 页面选择勾销填写的备注
		balanceSheetRecordInsert.setMark(insertObject.getMark());
		balanceSheetRecordInsert.setProduceType(insertObject.getProduceType());
		balanceSheetRecordInsert.setProjectId(contract.getProjectId());
		balanceSheetRecordInsert.setLastModifiedBy(SecurityUtils.getCurrentLogin().getUserId());
		balanceSheetRecordInsert.setLastModifiedDtm(new Date());

		balanceSheetWriteMapper.insertSelective(balanceSheetRecordInsert);
	}

	/**
	 * 
	 * 
	 * [简要描述]：非抄表月结账单勾销</br>
	 * [详细描述]：</br>
	 * [作者]：Crystal(2017-08-28)</br>
	 *
	 * @param req
	 * @throws LandseaException
	 *
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
	public void noneMeterReadCancel(NoneMeterReadCancelReq req)
			throws LandseaException
	{
		try
		{
			// 不合法情况如下
			// 校验账单是否为有效的（账单未支付、非首付账单、非房租和服务费、房屋押金、水费押金等系统生成的费项）
			Integer id = req.getId();
			MonthlyBill monthlyBill = monthlyBillReadMapper.selectByPrimaryKey(id);
			if (null == monthlyBill)
			{
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|非抄表月结账单不存在.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500016);
			}
			Integer contractId = monthlyBill.getContractId();
			String billMonth = monthlyBill.getBillMonth();
			String type = monthlyBill.getExpenseType();
			// 如果为滞纳金，则不允许勾销
			if ("_CTBI13".equals(type))
			{
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|非抄表月结账单不存在.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500016);
			}
			// 查出账单
			// 账单月里面的月份跟账单里面的账单月相差一个月
			String lastBillMonth = LandSeaUtil.getBillMonth(billMonth);
			Bill bill = billReadMapper.selectByContractIdAndBillMonth(contractId, lastBillMonth);

			// 如果账单没有录进bill表中
			if (null == bill)
			{
				noBillRecordProcess(req);
				return;
			}

			// 查出账单详情
			BillDetail billDetail = billDetailReadMapper.selectByBillIdAndType(bill.getId(), type);

			if (null == billDetail)
			{
				// 账单不存在
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|非抄表月结账单不存在.id=" + id);
				throw LandseaException.createException(BillResultCode.E00450003);
			}
			if (("首期账单").equals(bill.getName()))
			{
				// 首付账单
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|首付账单，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E00450004);
			}
			LOGGER.info("NoneMeterDetailNo:"+billDetail.getDetailNo());
			// 账单已支付
			Double receivableMoney = bill.getReceivableMoney();
			Double amountReceived = bill.getAmountReceived();
			if (amountReceived.doubleValue() != 0)
			{
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|账单已支付或者部分支付，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E00450005);
			}

			// 合法
			if (!BillTypeChecker.isNoneRecordBillType(type))
			{
				LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|系统生成费项，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E00450006);
			}

			Double cancelMoney = req.getCancelMoney();
			// 要转换成0.00
			cancelMoney = LandSeaUtil.get2Double(cancelMoney);


			// 勾销金额为0
			if (0.00d == cancelMoney.doubleValue())
			{
				Double money = billDetail.getMoney();

				// 新增负数到原始金额记录中
				MonthlyBillInsertBalanceSheet insertBalanceSheet = new MonthlyBillInsertBalanceSheet();
				insertBalanceSheet.setBill(bill);
				insertBalanceSheet.setBillDetail(billDetail);
				insertBalanceSheet.setProduceType(ProduceType.CANCEL);
				insertBalanceSheet.setAmountReceived(-billDetail.getMoney());
				insertBalanceSheet.setReceivableMoney(-billDetail.getMoney());
				insertBalanceSheet.setBillStatus(BillStatusEnum.BIST2.getCode());
				insertBalanceSheet.setMark(req.getMark());
				insertBalanceSheet.setPayTime(new Date());
				insertNoneMeterBalanceSheet(insertBalanceSheet);

				// 删除账单详情
				billDetailWriteMapper.deleteByPrimaryKey(billDetail);

				monthlyBillWriteMapper.deleteByContractIdAndBillMonth(monthlyBill);
				// 修改账单表金额
				Bill bill1 = new Bill();
				bill1.setId(bill.getId());

				bill1.setReceivableMoney(Arith.sub(receivableMoney.doubleValue(), money.doubleValue()));
				// 此处的创建时间一定不能改，bill表中的createedDtm计算滞纳金要用
				bill1.setCreatedDtm(null);
				bill1.setCreatedBy(null);
				billWriteMapper.updateByPrimaryKeySelective(bill1);

				//将独立账单的上一笔钱修改成购销状态
				monUpdateProduceType(bill.getId(),bill.getBillMonth(), type,billDetail.getDetailNo());
				// 平帐处理
				monUpdateBalanceSheet(bill.getId(), type);
				return;
			}
			// 勾销金额不为0
			// 新增负数到原始金额记录中
			MonthlyBillInsertBalanceSheet insertBalanceSheet = new MonthlyBillInsertBalanceSheet();
			insertBalanceSheet.setBill(bill);
			insertBalanceSheet.setBillDetail(billDetail);
			insertBalanceSheet.setProduceType(ProduceType.CANCEL);
			insertBalanceSheet.setAmountReceived(0.00);
			insertBalanceSheet.setReceivableMoney(-billDetail.getMoney());
			insertBalanceSheet.setBillStatus(BillStatusEnum.BIST3.getCode());
			insertBalanceSheet.setMark(req.getMark());
			insertNoneMeterBalanceSheet(insertBalanceSheet);
			//将独立账单的上一笔钱修改成购销状态
			monUpdateProduceType(bill.getId(),bill.getBillMonth(), type,billDetail.getDetailNo());
			// 新增勾销金额记录到应收实收汇总表
			insertBalanceSheet.setReceivableMoney(cancelMoney);
			insertBalanceSheet.setProduceType(ProduceType.PAY);
			insertNoneMeterBalanceSheet(insertBalanceSheet);

			// 修改账单详情表
			Double updateMoney = Arith.add(Arith.sub(receivableMoney, billDetail.getMoney()), cancelMoney);
			billDetail.setMoney(cancelMoney);
			billDetailWriteMapper.updateByPrimaryKeySelective(billDetail);

			// 修改账单表金额
			Bill bill2 = new Bill();
			bill2.setId(bill.getId());
			bill2.setReceivableMoney(updateMoney);
			billWriteMapper.updateByPrimaryKeySelective(bill2);

			MonthlyBill updateMonthlyBill = new MonthlyBill();
			updateMonthlyBill.setId(id);
			updateMonthlyBill.setBillPrice(cancelMoney);
			monthlyBillWriteMapper.updateByPrimaryKeySelective(updateMonthlyBill);

		}
		catch (LandseaException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			LOGGER.error("noneMeterReadCancel|月结非抄表账单勾销错误.", e);
			throw LandseaException.createException(BillResultCode.E00450007, e);
		}
	}

	private void monUpdateProduceType(Integer id, String billMonth,String type,String billNo)
	{
		//update ProduceType=2
		BalanceSheetRecord record = new BalanceSheetRecord();
		record.setBillId(id);
		record.setBillType(LandeaConstants.BillType.MONTHLY_BILL);
		record.setBillMonth(billMonth);
		record.setExpenditureCode(type);
		record.setProduceType(ProduceType.CANCEL);
		record.setBillNo(billNo);
		record.setLastModifiedBy(SecurityUtils.getCurrentLogin().getUserId());
		record.setLastModifiedDtm(new Date());
		balanceSheetWriteMapper.updateByBillNo(record);

	}

	// 非抄表类月结的平帐处理
	private void monUpdateBalanceSheet(Integer id, String type)
	{
		Bill bill = billReadMapper.selectKey(id);
		Map<String, Object> editRecord = new HashMap<String, Object>();
		editRecord.put("billId", id);
		editRecord.put("billType", LandeaConstants.BillType.MONTHLY_BILL);
		editRecord.put("billMonth", bill.getBillMonth());
		editRecord.put("expenditureCode", type);
		List<BalanceSheetRecord> balanceSheetRecords = balanceSheetRecordReadMapper.selectEditRecord(editRecord);
		if (null == balanceSheetRecords)
		{
			return;
		}
		for (BalanceSheetRecord balanceSheetRecord : balanceSheetRecords)
		{
			if(balanceSheetRecord.getProduceType()==ProduceType.CANCEL){
				continue;
			}
			balanceSheetRecord.setAmountReceived(balanceSheetRecord.getReceivableMoney());
			balanceSheetRecord.setBillStatus(BillStatusEnum.BIST2.getCode());
			balanceSheetRecord.setProduceType(ProduceType.CANCEL);
			balanceSheetRecord.setPayTime(new Date());
			balanceSheetWriteMapper.updateByPrimaryKeySelective(balanceSheetRecord);
		}
		
	}  


	// 非抄表类数据没有生成月结账单的处理
	private void noBillRecordProcess(NoneMeterReadCancelReq req)
	{
		Double cancelMoney = req.getCancelMoney();
		// 要转换成0.00
		cancelMoney = LandSeaUtil.get2Double(cancelMoney);
		// 勾销金额为0
		if (0.00d == cancelMoney.doubleValue())
		{
			// 直接删除MonthlyBill表中的数据
			MonthlyBill monthlyBill = monthlyBillReadMapper.selectByPrimaryKey(req.getId());
			monthlyBillWriteMapper.deleteByPrimaryKey(monthlyBill);

			return;
		}
		// 购销金额不为0，修改MonthlyBill表中的数据

		MonthlyBill updateMonthlyBill = new MonthlyBill();
		updateMonthlyBill.setId(req.getId());
		updateMonthlyBill.setStartTime(req.getStartTime());
		updateMonthlyBill.setEndTime(req.getEndTime());
		updateMonthlyBill.setBillPrice(cancelMoney);
		updateMonthlyBill.setComment(req.getMark());
		monthlyBillWriteMapper.updateByPrimaryKeySelective(updateMonthlyBill);

	}

	private void insertNoneMeterBalanceSheet(MonthlyBillInsertBalanceSheet insertBalanceSheet)
	{
		BalanceSheetRecord balanceSheetRecordInsert = new BalanceSheetRecord();
		Bill bill = insertBalanceSheet.getBill();
		BillDetail billDetail = insertBalanceSheet.getBillDetail();
		balanceSheetRecordInsert.setBillId(bill.getId());
		// 应收金额
		Double amountReceived = LandSeaUtil.get2Double(insertBalanceSheet.getAmountReceived());
		balanceSheetRecordInsert.setAmountReceived(amountReceived);
		// 已收金额
		Double receivableMoney = LandSeaUtil.get2Double(insertBalanceSheet.getReceivableMoney());
		balanceSheetRecordInsert.setReceivableMoney(receivableMoney);
		balanceSheetRecordInsert.setBillMonth(bill.getBillMonth());
		balanceSheetRecordInsert.setBillNo(billDetail.getDetailNo());
		balanceSheetRecordInsert.setBillName(bill.getName());
		// 账单的类型
		balanceSheetRecordInsert.setBillType(LandeaConstants.BillType.MONTHLY_BILL);
		// 非抄表月结账单表中状态是支付失败
		balanceSheetRecordInsert.setBillStatus(insertBalanceSheet.getBillStatus());

		Contract contract = contractReadMapper.selectByPrimaryKey(bill.getContractId());
		if (null != contract)
		{
			balanceSheetRecordInsert.setContractNo(contract.getContractNo());
			balanceSheetRecordInsert.setContractId(contract.getId());
		}
		else
		{
			LOGGER.error("noneMeterReadCancel|月结账单勾销|合同不存在.ContractId=" + bill.getContractId());
		}
		balanceSheetRecordInsert.setRoomId(contract.getRoomId());
		Room room = roomReadMapper.selectByPrimaryKey(contract.getRoomId());
		balanceSheetRecordInsert.setHouseNum(room.getHouseNum());

		balanceSheetRecordInsert.setCreateTime(bill.getCreatedDtm());
		balanceSheetRecordInsert.setEndTime(billDetail.getDateEnd());
		balanceSheetRecordInsert.setStartTime(billDetail.getDateBegin());

		balanceSheetRecordInsert.setExpenditureCode(billDetail.getType());
		String expenditure = balanceSheetRecordReadMapper.selectExpenditure(billDetail.getType());
		balanceSheetRecordInsert.setExpenditure(expenditure);
		// 支付时间判断
		if (null != insertBalanceSheet.getPayTime())
		{
			balanceSheetRecordInsert.setPayTime(insertBalanceSheet.getPayTime());
		}

		// 页面选择勾销填写的备注
		balanceSheetRecordInsert.setMark(insertBalanceSheet.getMark());
		balanceSheetRecordInsert.setProduceType(insertBalanceSheet.getProduceType());
		balanceSheetRecordInsert.setProjectId(contract.getProjectId());
		balanceSheetRecordInsert.setLastModifiedBy(SecurityUtils.getCurrentLogin().getUserId());
		balanceSheetRecordInsert.setLastModifiedDtm(new Date());

		balanceSheetWriteMapper.insertSelective(balanceSheetRecordInsert);
	}

	/**
	 * 
	 * [简要描述]：查出读数</br>
	 * [详细描述]：查出抄表类的上次读数</br>
	 * [作者]：Crystal(2017-08-30)</br>
	 * @return
	 * @throws LandseaException
	 * @throws ParseException
	 *
	 */
	public Map<String, Object> getMeterRead(Integer monthlyBillId)
			throws LandseaException, ParseException
	{
		MonthlyBill monthlyBill = monthlyBillReadMapper.selectByPrimaryKey(monthlyBillId);
		Map<String, Object> pmap = new HashMap<String, Object>();
		pmap.put("roomId", monthlyBill.getRoomId());
		pmap.put("expenseType", monthlyBill.getExpenseType());

		DateUtil dateUtil = new DateUtil();
		String billMonth = dateUtil.getDateFormat(monthlyBill.getBillMonth());
		pmap.put("billMonth", billMonth);
		Map<String, Object> meterResp = new HashMap<String, Object>();
		// 本次抄表数据
		MeterReadResp currentResp = expensesReadMapper.selectCurrentMeterRead(pmap);
		meterResp.put("currentResp", currentResp);
		// 上次抄表数据
		List<Expenses> expensesList = expensesReadMapper.selectMeterRead(pmap);
		if (CollectionUtils.isEmpty(expensesList))
		{
			//如果expenses表中没有小于本月的抄表记录，那么上一次抄表读数从交割单里面获取
			pmap.put("contractId", monthlyBill.getContractId());
			MeterReadResp lastResp = checkFeeListReadMapper.selectByContractIdAndType(pmap);
			meterResp.put("lastResp", lastResp);
		}
		else {   
			//否则只能从expenses表中获取数据
			MeterReadResp lastResp = expensesReadMapper.selectLastMeterRead(pmap);
			meterResp.put("lastResp", lastResp);
		}
		return meterResp;
	}

	/**
	 * 
	 * 
	 * [简要描述]：抄表月结账单勾销</br>
	 * [详细描述]：</br>
	 * [作者]：Crystal(2017-08-29)</br>
	 *
	 * @param req
	 * @throws LandseaException
	 *
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
	public void meterReadCancel(MeterReadCancelReq req)
			throws LandseaException
	{
		try
		{
			// 不合法情况
			// 校验账单是否为有效的（账单未支付、非首付账单、非房租和服务费、房屋押金、水费押金等系统生成的费项）
			Integer id = req.getId();
			MonthlyBill monthlyBill = monthlyBillReadMapper.selectByPrimaryKey(id);
			if (null == monthlyBill)
			{
				// 账单不存在
				LOGGER.error("meterReadCancel|抄表月结账单勾销|抄表月结账单不存在.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500011);
			}
			Integer contractId = monthlyBill.getContractId();
			String billMonth = monthlyBill.getBillMonth();
			String type = monthlyBill.getExpenseType();

			HashMap<String, Object> pmap = new HashMap<String, Object>();
			pmap.put("roomId", monthlyBill.getRoomId());
			pmap.put("expenseType", type);
			Map<String, Object> meterReadResps = getMeterRead(id);
			MeterReadResp resp = (MeterReadResp)meterReadResps.get("lastResp");
			MeterReadResp currentResp = (MeterReadResp)meterReadResps.get("currentResp");
			if (resp.getDegree().doubleValue() > req.getMeterData().doubleValue())
			{
				LOGGER.error("meterReadCancel|抄表月结账单勾销|当前抄表度数小于上次抄表度数，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500014);
			}
			LOGGER.info("前台录入的数据：req.getMeterData()" + req.getMeterData());
			LOGGER.info("上次抄表的数据：resp.getDegree()" + resp.getDegree());
			Double cancleMoney = 0.00;
			if (type.equals(BillTypeEnum.CTBI1.getCode()))
			{
				cancleMoney =
						LandSeaUtil.get2Double(Arith.sub(req.getMeterData(), resp.getDegree()) * resp.getWaterPrice());
				LOGGER.info("计算勾销的水费金额：cancleMoney" + cancleMoney);
			}
			else if (type.equals(BillTypeEnum.CTBI2.getCode()))
			{
				cancleMoney =
						LandSeaUtil.get2Double(Arith.sub(req.getMeterData(), resp.getDegree()) * resp.getElectricPrice());
				LOGGER.info("计算勾销的电费金额：cancleMoney" + cancleMoney);
			}
			else if (type.equals(BillTypeEnum.CTBI3.getCode()))
			{
				cancleMoney =
						LandSeaUtil.get2Double(Arith.sub(req.getMeterData(), resp.getDegree()) * resp.getGasPrice());
				LOGGER.info("计算勾销的燃气费金额：cancleMoney" + cancleMoney);
			}
			else if (type.equals(BillTypeEnum.CTBI4.getCode()))
			{
				cancleMoney =
						LandSeaUtil.get2Double(Arith.sub(req.getMeterData(), resp.getDegree()) * resp.getHotWaterPrice());
				LOGGER.info("计算勾销的热水费金额：cancleMoney" + cancleMoney);
			}
			Double meterMoney = req.getMeterMoney();
			if (meterMoney.doubleValue() != cancleMoney.doubleValue())
			{
				LOGGER.error("meterReadCancel|抄表月结账单勾销|费用金额计算出错，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500015);
			}

			// 查出账单
			// 账单月里面的月份跟账单里面的账单月相差一个月
			String lastBillMonth = LandSeaUtil.getBillMonth(billMonth);
			Bill bill = billReadMapper.selectByContractIdAndBillMonth(contractId, lastBillMonth);
			// 如果账单没有录进bill表中
			if (null == bill)
			{
				noBillReadRecordProcess(req, monthlyBill, resp,currentResp);
				return;
			}
			// 查出账单详情
			BillDetail billDetail = billDetailReadMapper.selectByBillIdAndType(bill.getId(), type);
			if (null == billDetail)
			{
				// 账单不存在
				LOGGER.error("meterReadCancel|抄表月结账单勾销|抄表月结账单不存在.billDetail id=" + billDetail.getId());
				throw LandseaException.createException(BillResultCode.E004500011);
			}
			// 查询滞纳金是否不为0，是的话不允许勾销，反之可以勾销
			List<BillDetail> billDetails = billDetailReadMapper.getBillDetail(bill.getId());
			for (BillDetail billDetail1 : billDetails)
			{
				if ("_CTBI13".equals(billDetail1.getType()) && 0.0 != billDetail1.getMoney())
				{
					LOGGER.error("noneMeterReadCancel|非抄表月结账单勾销|非抄表月结账单不存在.id=" + id);
					throw LandseaException.createException(BillResultCode.E004500016);
				}
			}
			if (("首期账单").equals(bill.getName()))
			{
				// 首付账单
				LOGGER.error("meterReadCancel|抄表月结账单勾销|首付账单，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500012);
			}
			// 账单已支付
			Double receivableMoney = bill.getReceivableMoney();
			Double amountReceived = bill.getAmountReceived();
			if (amountReceived.doubleValue() != 0)
			{
				LOGGER.error("meterReadCancel|抄表月结账单勾销|账单已支付或者部分支付，无法勾销.id=" + id);
				throw LandseaException.createException(BillResultCode.E004500013);
			}
			// 合法
			// 新增负数到原始金额记录中
			MonthlyBillInsertBalanceSheet insertBalanceSheet = new MonthlyBillInsertBalanceSheet();
			insertBalanceSheet.setBill(bill);
			insertBalanceSheet.setBillDetail(billDetail);
			insertBalanceSheet.setBillStatus(BillStatusEnum.BIST3.getCode());
			insertBalanceSheet.setMark(req.getMark());
			insertBalanceSheet.setAmountReceived(0.00);
			insertBalanceSheet.setReceivableMoney(-billDetail.getMoney());
			insertBalanceSheet.setProduceType(ProduceType.CANCEL);
			insertNoneMeterBalanceSheet(insertBalanceSheet);
			//将独立账单的上一笔钱修改成购销状态
			monUpdateProduceType(bill.getId(),bill.getBillMonth(), type,billDetail.getDetailNo());
			// 新增勾销金额记录到应收实收汇总表
			insertBalanceSheet.setReceivableMoney(req.getMeterMoney());
			insertBalanceSheet.setProduceType(ProduceType.PAY);
			insertNoneMeterBalanceSheet(insertBalanceSheet);
			Double updateMoney = Arith.add(Arith.sub(receivableMoney, billDetail.getMoney()), meterMoney);

			// 修改账单详情表
			BillDetail detail = new BillDetail();
			detail.setId(billDetail.getId());
			detail.setMoney(meterMoney);
			billDetailWriteMapper.updateByPrimaryKeySelective(detail);
			// 修改账单表金额
			Bill bill2 = new Bill();
			bill2.setId(bill.getId());
			bill2.setReceivableMoney(updateMoney);
			// 此处的创建时间一定不能改，bill表中的createedDtm计算滞纳金要用
			bill2.setCreatedDtm(null);
			bill2.setCreatedBy(null);
			billWriteMapper.updateByPrimaryKeySelective(bill2);
			// 修改月账单表金额为勾销金额/修改抄表度数
			MonthlyBill mBill = new MonthlyBill();
			mBill.setId(id);
			mBill.setConsumption(Arith.sub(req.getMeterData(), resp.getDegree()));
			mBill.setBillPrice(meterMoney);
			mBill.setEndTime(req.getEndDate());
			monthlyBillWriteMapper.updateByPrimaryKeySelective(mBill);
			// 修改记录抄表的记录
			Expenses expenses = new Expenses();
			expenses.setId(currentResp.getId());
			expenses.setDegree(req.getMeterData());
			expenses.setReadMeterTime(req.getEndDate());
			expensesWriteMapper.updateByPrimaryKeySelective(expenses);

		}
		catch (LandseaException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			LOGGER.error("noneMeterReadCancel|月结抄表账单勾销错误.", e);
			throw LandseaException.createException(BillResultCode.E004500010, e);
		}

	}

	// 抄表类数据没有生成月结账单的处理
	private void noBillReadRecordProcess(MeterReadCancelReq req, MonthlyBill monthlyBill, MeterReadResp resp, MeterReadResp currentResp)
			throws LandseaException
	{
		Integer id = req.getId();

		// 修改月账单表金额为勾销金额/修改抄表度数
		MonthlyBill mBill = new MonthlyBill();
		mBill.setId(id);
		mBill.setConsumption(Arith.sub(req.getMeterData(), resp.getDegree()));
		mBill.setBillPrice(req.getMeterMoney());
		mBill.setEndTime(req.getEndDate());
		mBill.setComment(req.getMark());
		monthlyBillWriteMapper.updateByPrimaryKeySelective(mBill);
		// 修改记录抄表的记录
		Expenses expenses = new Expenses();
		expenses.setId(currentResp.getId());
		expenses.setDegree(req.getMeterData());
		expenses.setReadMeterTime(req.getEndDate());
		expensesWriteMapper.updateByPrimaryKeySelective(expenses);
	}

	/**
	 * 
	 * [简要描述]：查询月结表滞纳金</br>
	 * [详细描述]：</br>
	 * [作者]：Aaron(2017-09-23)</br>
	 *
	 * @param contractId
	 * @return
	 * @throws LandseaException
	 *
	 */
	public Map<String, String> getLateFeeMonthMap(Integer contractId)
			throws LandseaException
	{
		try
		{
			List<MonthlyBill> monthBillList = monthlyBillReadMapper.selectBillMonthByContractId(contractId);

			// key：billMonth value：1存在滞纳金 0不存在滞纳金
			Map<String, String> resultMap = new HashMap<String, String>();

			if (CollectionUtils.isEmpty(monthBillList))
			{
				return resultMap;
			}

			// 现将所有billMonth放入
			for (MonthlyBill monthBill : monthBillList)
			{
				String billMonth = monthBill.getBillMonth();

				if (null == resultMap.get(billMonth))
				{
					resultMap.put(billMonth, "0");
				}
				// 如果存在滞纳金
				if (BillTypeEnum.CTBI13.getCode().equals(monthBill.getExpenseType()))
				{
					resultMap.put(billMonth, "1");
				}
			}

			return resultMap;
		}
		catch (Exception e)
		{
			LOGGER.error("getLateFeeMonthMap|查询月结表失败.", e);
			throw LandseaException.createException(BillResultCode.E004500017, e);
		}
	}
}
